<!DOCTYPE html>
<html lang="zh-CN">
  <head>
  <meta charset="UTF-8">
  <meta 
    name="viewport"
    content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
  <meta 
    http-equiv="X-UA-Compatible" 
    content="ie=edge">
  <meta 
    name="theme-color" 
    content="#fff" 
    id="theme-color">
  <meta 
    name="description" 
    content="霜序廿的个人网站">
  <link 
    rel="icon" 
    href="https://api2.mubu.com/v3/photo/654b368e-b847-4122-982c-86d90b3f5275.jpg">
  <title>v-model源码解析(超详细)</title>
  
    
      <meta 
        property="og:title" 
        content="v-model源码解析(超详细)">
    
    
      <meta 
        property="og:url" 
        content="https://shuangxunian.github.io/2021/08/14/VmodelSourceCodeParsing-SuperDetailed/index.html">
    
    
      <meta 
        property="og:img" 
        content="https://api2.mubu.com/v3/photo/654b368e-b847-4122-982c-86d90b3f5275.jpg">
    
    
      <meta 
        property="og:img" 
        content="如题目">
    
    
      <meta 
        property="og:type" 
        content="article">
      <meta 
        property="og:article:published_time" 
        content="2021-08-14">
      <meta 
        property="og:article:modified_time" 
        content="2021-08-14">
      <meta 
        property="og:article:author" 
        content="霜序廿">
      
        
          <meta 
            property="og:article:tag" 
            content="js">
        
          <meta 
            property="og:article:tag" 
            content="vue">
        
      
    
  
  <script>
    function loadScript(url, cb) {
      var script = document.createElement('script');
      script.src = url;
      if (cb) script.onload = cb;
      script.async = true;
      document.body.appendChild(script);
    }
    function loadCSS(href, data, attr) {
      var sheet = document.createElement('link');
      sheet.ref = 'stylesheet';
      sheet.href = href;
      sheet.dataset[data] = attr;
      document.head.appendChild(sheet);
    }
    function changeCSS(cssFile, data, attr) {
      var oldlink = document.querySelector(data);
      var newlink = document.createElement("link");
      newlink.setAttribute("rel", "stylesheet");
      newlink.setAttribute("href", cssFile);
      newlink.dataset.prism = attr;
      document.head.replaceChild(newlink, oldlink);
    }
  </script>
  
    
      
      
      
      
        
        
        
        <script>
          function prismThemeChange() {
            if(document.getElementById('theme-color').dataset.mode === 'dark') {
              if(document.querySelector('[data-prism]')) {
                changeCSS('/js/lib/prism/prism-tomorrow.min.css', '[data-prism]', 'prism-tomorrow');
              } else {
                loadCSS('/js/lib/prism/prism-tomorrow.min.css', 'prism', 'prism-tomorrow');
              }
            } else {
              if(document.querySelector('[data-prism]')) {
                changeCSS('/js/lib/prism/prism.min.css', '[data-prism]', 'prism');
              } else {
                loadCSS('/js/lib/prism/prism.min.css', 'prism', 'prism');
              }
            }
          }
          prismThemeChange()
        </script>
      
      
        
        <link rel="stylesheet" href="/js/lib/prism/prism-line-numbers.min.css">
      
    
  
  <script>
    // control reverse button
    var reverseDarkList = {
      dark: 'light',
      light: 'dark'
    };
    var themeColor = {
      dark: '#1c1c1e',
      light: '#fff'
    }
    // get the data of css prefers-color-scheme
    var getCssMediaQuery = function() {
      return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
    };
    // reverse current darkmode setting function
    var reverseDarkModeSetting = function() {
      var setting = localStorage.getItem('user-color-scheme');
      if(reverseDarkList[setting]) {
        setting = reverseDarkList[setting];
      } else if(setting === null) {
        setting = reverseDarkList[getCssMediaQuery()];
      } else {
        return;
      }
      localStorage.setItem('user-color-scheme', setting);
      return setting;
    };
    // apply current darkmode setting
  </script>
  
    <script>
      var setDarkmode = function(mode) {
      var setting = mode || localStorage.getItem('user-color-scheme');
      if(setting === getCssMediaQuery()) {
        document.documentElement.removeAttribute('data-user-color-scheme');
        localStorage.removeItem('user-color-scheme');
        document.getElementById('theme-color').content = themeColor[setting];
        document.getElementById('theme-color').dataset.mode = setting;
        prismThemeChange();
      } else if(reverseDarkList[setting]) {
        document.documentElement.setAttribute('data-user-color-scheme', setting);
        document.getElementById('theme-color').content = themeColor[setting];
        document.getElementById('theme-color').dataset.mode = setting;
        prismThemeChange();
      } else {
        document.documentElement.removeAttribute('data-user-color-scheme');
        localStorage.removeItem('user-color-scheme');
        document.getElementById('theme-color').content = themeColor[getCssMediaQuery()];
        document.getElementById('theme-color').dataset.mode = getCssMediaQuery();
        prismThemeChange();
      }
    };
    setDarkmode();
    </script>
  
  
  <link rel="preload" href="//at.alicdn.com/t/font_1946621_i1kgafibvw.css" as="style" >
  <link rel="preload" href="//at.alicdn.com/t/font_1952792_89b4ac4k4up.css" as="style" >
  
  
    <link rel="preload" href="/js/lib/lightbox/baguetteBox.min.js" as="script">
    <link rel="preload" href="/js/lib/lightbox/baguetteBox.min.css" as="style" >
  
  
    <link rel="preload" href="/js/lib/lozad.min.js" as="script">
  
  
  
  
  
  
  
  <link rel="stylesheet" href="/css/main.css">
  
  <link rel="stylesheet" href="//at.alicdn.com/t/font_1946621_i1kgafibvw.css">
  
  <link rel="stylesheet" href="//at.alicdn.com/t/font_1952792_89b4ac4k4up.css">
  
    <link rel="stylesheet" href="/js/lib/lightbox/baguetteBox.min.css">
  
<meta name="generator" content="Hexo 5.4.0"></head>

  <body>
    <div class="wrapper">
       
      <nav class="navbar">
  <div class="navbar-logo">
    <span class="navbar-logo-main">
      
        <img 
          class="navbar-logo-img" 
          src="https://api2.mubu.com/v3/photo/654b368e-b847-4122-982c-86d90b3f5275.jpg" 
          alt="blog logo">
      
      <span class="navbar-logo-dsc">霜序廿的个人网站</span>
    </span>
  </div>
  <div class="navbar-menu">
    
      <a 
        href="/" 
        class="navbar-menu-item">
        
          首页
        
      </a>
    
      <a 
        href="/archives" 
        class="navbar-menu-item">
        
          归档
        
      </a>
    
      <a 
        href="/tags" 
        class="navbar-menu-item">
        
          标签
        
      </a>
    
      <a 
        href="/categories" 
        class="navbar-menu-item">
        
          分类
        
      </a>
    
      <a 
        href="/about" 
        class="navbar-menu-item">
        
          关于
        
      </a>
    
      <a 
        href="/links" 
        class="navbar-menu-item">
        
          友链
        
      </a>
    
    <a 
      class="navbar-menu-item darknavbar" 
      id="dark">
      <i class="iconfont icon-weather"></i>
    </a>
    <a 
      class="navbar-menu-item searchnavbar" 
      id="search">
      <i 
        class="iconfont icon-search" 
        style="font-size: 1.2rem; font-weight: 400;">
      </i>
    </a>
  </div>
</nav> 
      
      <div 
        id="local-search" 
        style="display: none">
        <input
          class="navbar-menu-item"
          id="search-input"
          placeholder="请输入搜索内容..." />
        <div id="search-content"></div>
      </div>
      
      <div class="section-wrap">
        <div class="container">
          <div class="columns">
            <main class="main-column">
<article class="card card-content">
  <header>
    <h1 class="post-title">
      v-model源码解析(超详细)
    </h1>
  </header>
  <div class="post-meta post-show-meta">
    <time datetime="2021-08-14T08:07:28.761Z">
      <i 
        class="iconfont icon-calendar" 
        style="margin-right: 2px;">
      </i>
      <span>2021-08-14</span>
    </time>
    
      <span class="dot"></span>
      
        <a 
          href="/categories/%E6%8A%80%E6%9C%AF%E6%96%87%E7%AB%A0/" 
          class="post-meta-link">
          技术文章
        </a>
      
    
    
      <span class="dot"></span>
      <span>4.3k 字</span>
    
  </div>
  
    <div 
      class="post-meta post-show-meta" 
      style="margin-top: -10px;">
      <div style="display: flex; align-items: center;">
        <i 
          class="iconfont icon-biaoqian" 
          style="margin-right: 2px; font-size: 1.15rem;">
        </i>
        
          
          <a 
            href="/tags/js/" 
            class="post-meta-link">
            js
          </a>
        
          
            <span class="dot"></span>
          
          <a 
            href="/tags/vue/" 
            class="post-meta-link">
            vue
          </a>
        
      </div>
    </div>
  
  </header>
  <div 
    id="section" 
    class="post-content">
    <h2 id="抛出问题"><a href="#抛出问题" class="headerlink" title="抛出问题"></a>抛出问题</h2><p>我们先来看一下下面这段代码</p>
<pre class="line-numbers language-html" data-language="html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>message<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>&#123;&#123; info.message &#125;&#125;<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>info.message<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>change<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>click<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">></span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
  <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">&#123;</span>
    <span class="token function">data</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
      <span class="token keyword">return</span> <span class="token punctuation">&#123;</span>
        info<span class="token operator">:</span> <span class="token punctuation">&#123;</span><span class="token punctuation">&#125;</span>
      <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span><span class="token punctuation">,</span>
    methods<span class="token operator">:</span> <span class="token punctuation">&#123;</span>
      <span class="token function">change</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>info<span class="token punctuation">.</span>message <span class="token operator">=</span> <span class="token string">'hello world'</span>
      <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span>
  <span class="token punctuation">&#125;</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>上述代码很简单，就不做过多的解释了。</p>
<h2 id="问题重现步骤"><a href="#问题重现步骤" class="headerlink" title="问题重现步骤"></a>问题重现步骤</h2><p>我现在对上述代码做两种操作：</p>
<ol>
<li>一进页面先在输入框中输入<code>hello vue</code></li>
<li>一进页面先点击 click 按钮进行赋值操作，再在输入框中输入<code>hello vue</code></li>
</ol>
<p>上述两种情况分别会出现什么现象呢？</p>
<p>第一种操作，当我们在输入框中输入<code>hello vue</code>的时候，class 为 message 的 div 中会联动出现<code>hello vue</code>，也就是说 info 中的<code>message</code>属性是响应式的</p>
<p>第二种操作，当我们先进行赋值操作，之后无论在输入框中输入什么内容，class 为<code>message</code>的 div 中都不会联动出现任何值，也就是说 info 中的 message 属性非响应式的</p>
<h2 id="问题引发的猜想"><a href="#问题引发的猜想" class="headerlink" title="问题引发的猜想"></a>问题引发的猜想</h2><p>查阅 vue 官方文档我们得知 vue 在初始化的时候会对 data 中所有已经定义的对象及其子属性进行遍历，给他们添加 getter 和 setter，使得他们变成响应式的（关于响应式这块之后会单开文章进行解析），但是 vue 不能检测对象属性的添加或删除。但是，可以使用 <code>Vue.set(object, propertyName, value)</code> 方法向嵌套对象添加响应式属性</p>
<p>基于上述描述，我们先看第一种操作。直接在输入框中输入<code>hello vue</code>，class 为 <code>message</code> 的 div 中会联动出现<code>hello vue</code>。但是我们看 data 中只定义了 info 对象，其中并没有定义 message 属性，message 属于新增属性。根据 vue 官方文档中说的，vue 不能检测对象属性的添加或删除，所以我猜测 vue 底层在解析 v-model 指令的时候,每当触发表单元素的监听事件(例如 input 事件)，就会有 Vue.set() 操作，从而触发 setter</p>
<p>带着这个猜测，我们来看第二种操作。一进页面先点击 click 按钮，对 info.message 进行赋值，message 属于新增属性，根据官方文档中说的，此时 message 并不是响应式的，没问题。但是我们接着在 input 输入框中输入值，class 为<code>message</code>的 div 中没有联动出现任何值，根据我们对于第一种情况的猜测，当输入框监听到 input 事件的时候，会对 info 中的 message 进行 Vue.set() 操作，所以理论上就算一开始 click 中是对新增属性 message 直接赋值的，导致该属性并非响应式的，在经过输入框 input 事件中的 Vue.set() 操作之后，应该会变成响应式的，而现在呈现出来的情况并不是这样的啊，这是为什么呢？</p>
<p>聪明的你们应该已经猜到在 Vue.set() 底层源码中，应该是会判断 message 属性是否一开始就在 info 中，如果存在就只是进行单纯的赋值，不存在的话在进行响应式操作，绑定 getter 和 setter</p>
<p>但是光猜测肯定是不够的，我们要用事实说话，做到有理有据。接下来我们就去看下 vue 源码中 v-model 这块，看看是不是如我们猜想的一样</p>
<h2 id="探索真相-源码分析"><a href="#探索真相-源码分析" class="headerlink" title="探索真相-源码分析"></a>探索真相-源码分析</h2><p>v-model 指令使用分为两种情况：一种是在表单元素上使用，另外一种是在组件上使用。我们今天分析的是第一种情况，也就是在表单元素上使用</p>
<h3 id="v-model实现机制"><a href="#v-model实现机制" class="headerlink" title="v-model实现机制"></a>v-model实现机制</h3><p>我们先简单说下 v-model 的机制：v-model 会把它关联的响应式数据（如 info.message ），动态地绑定到表单元素的 value 属性上，然后监听表单元素的 input 事件：当 v-model 绑定的响应数据发生变化时，表单元素的 value 值也会同步变化；当表单元素接受用户的输入时，input 事件会触发，input 的回调逻辑会把表单元素 value 最新值同步赋值给 v-model 绑定的响应式数据。</p>
<h3 id="v-model实现原理"><a href="#v-model实现原理" class="headerlink" title="v-model实现原理"></a>v-model实现原理</h3><p>我用来分析的源码是在vue官网安装模块里面下载的开发版本(2.6.10)，便于调试</p>
<h4 id="编译"><a href="#编译" class="headerlink" title="编译"></a>编译</h4><p>我们今天讲的内容其实就是把模版编译成 render 函数的一个流程，这里不会对每步流程都展开讲解，我可以给出一个步骤实现的流程，大家有兴趣的话可以根据这个流程来阅读代码，提高效率<br><code>$mount()-&gt;compileToFunctions()-&gt;compile()-&gt;baseCompile()</code></p>
<p>真正的编译过程都是在这个 baseCompile() 里面执行，执行步骤可以分为三个过程</p>
<ol>
<li>解析模版字符串生成AST<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">const</span> ast <span class="token operator">=</span> <span class="token function">parse</span><span class="token punctuation">(</span>template<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> options<span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></li>
<li>优化语法树<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token function">optimize</span><span class="token punctuation">(</span>ast<span class="token punctuation">,</span> options<span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></li>
<li>生成代码<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">const</span> code <span class="token operator">=</span> <span class="token function">generate</span><span class="token punctuation">(</span>ast<span class="token punctuation">,</span> options<span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></li>
</ol>
<p>然后我们看下generate里面的代码，这也是我们今天讲的重点</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">generate</span> <span class="token punctuation">(</span>
  <span class="token parameter">ast<span class="token punctuation">,</span>
  options</span>
<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
  <span class="token keyword">var</span> state <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CodegenState</span><span class="token punctuation">(</span>options<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">var</span> code <span class="token operator">=</span> ast <span class="token operator">?</span> <span class="token function">genElement</span><span class="token punctuation">(</span>ast<span class="token punctuation">,</span> state<span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token string">'_c("div")'</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token punctuation">&#123;</span>
    render<span class="token operator">:</span> <span class="token punctuation">(</span><span class="token string">"with(this)&#123;return "</span> <span class="token operator">+</span> code <span class="token operator">+</span> <span class="token string">"&#125;"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    staticRenderFns<span class="token operator">:</span> state<span class="token punctuation">.</span>staticRenderFns
  <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p><code>generate()</code> 首先通过 <code>genElement()-&gt;genData$2()-&gt;genDirectives()</code> 生成 code，再把 code 用 <code>with(this)&#123;return $&#123;code&#125;&#125;&#125;</code> 包裹起来,最终的到 render 函数。<br>接下来我们从<code>genDirectives()</code>开始讲解</p>
<h4 id="genDirectives"><a href="#genDirectives" class="headerlink" title="genDirectives"></a>genDirectives</h4><p>在模板的编译阶段，v-model 跟其他指令一样，会被解析到 el.directives 中，之后会通过<code>genDirectives</code>方法处理这些指令，我们这里从<code>genDirectives()</code>重点开始讲，至于怎么到这步，如果大家感兴趣的话，可以从<code>generate()</code>开始看</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">genDirectives</span> <span class="token punctuation">(</span><span class="token parameter">el<span class="token punctuation">,</span> state</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
  <span class="token keyword">var</span> dirs <span class="token operator">=</span> el<span class="token punctuation">.</span>directives<span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>dirs<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span> <span class="token keyword">return</span> <span class="token punctuation">&#125;</span>
  <span class="token keyword">var</span> res <span class="token operator">=</span> <span class="token string">'directives:['</span><span class="token punctuation">;</span>
  <span class="token keyword">var</span> hasRuntime <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
  <span class="token keyword">var</span> i<span class="token punctuation">,</span> l<span class="token punctuation">,</span> dir<span class="token punctuation">,</span> needRuntime<span class="token punctuation">;</span>
  <span class="token keyword">for</span> <span class="token punctuation">(</span>i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">,</span> l <span class="token operator">=</span> dirs<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i <span class="token operator">&lt;</span> l<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    dir <span class="token operator">=</span> dirs<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
    needRuntime <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
    <span class="token keyword">var</span> gen <span class="token operator">=</span> state<span class="token punctuation">.</span>directives<span class="token punctuation">[</span>dir<span class="token punctuation">.</span>name<span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>gen<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
      <span class="token comment">// compile-time directive that manipulates AST.</span>
      <span class="token comment">// returns true if it also needs a runtime counterpart.</span>
      needRuntime <span class="token operator">=</span> <span class="token operator">!</span><span class="token operator">!</span><span class="token function">gen</span><span class="token punctuation">(</span>el<span class="token punctuation">,</span> dir<span class="token punctuation">,</span> state<span class="token punctuation">.</span>warn<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>needRuntime<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
      hasRuntime <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
      res <span class="token operator">+=</span> <span class="token string">"&#123;name:\""</span> <span class="token operator">+</span> <span class="token punctuation">(</span>dir<span class="token punctuation">.</span>name<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"\",rawName:\""</span> <span class="token operator">+</span> <span class="token punctuation">(</span>dir<span class="token punctuation">.</span>rawName<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"\""</span> <span class="token operator">+</span> <span class="token punctuation">(</span>dir<span class="token punctuation">.</span>value <span class="token operator">?</span> <span class="token punctuation">(</span><span class="token string">",value:("</span> <span class="token operator">+</span> <span class="token punctuation">(</span>dir<span class="token punctuation">.</span>value<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"),expression:"</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>dir<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token punctuation">(</span>dir<span class="token punctuation">.</span>arg <span class="token operator">?</span> <span class="token punctuation">(</span><span class="token string">",arg:"</span> <span class="token operator">+</span> <span class="token punctuation">(</span>dir<span class="token punctuation">.</span>isDynamicArg <span class="token operator">?</span> dir<span class="token punctuation">.</span>arg <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token string">"\""</span> <span class="token operator">+</span> <span class="token punctuation">(</span>dir<span class="token punctuation">.</span>arg<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"\""</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token punctuation">(</span>dir<span class="token punctuation">.</span>modifiers <span class="token operator">?</span> <span class="token punctuation">(</span><span class="token string">",modifiers:"</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>dir<span class="token punctuation">.</span>modifiers<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"&#125;,"</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
  <span class="token punctuation">&#125;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>hasRuntime<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">']'</span>
  <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>我对上面这个代码打个断点，结合我们上面的代码例子，这样子看的更清楚，如下图：</p>
<p><img  srcset="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20300%20300'%3E%3C/svg%3E" data-src="https://api2.mubu.com/v3/document_image/17f04b1d-8f4a-4e8c-af4c-0ee49247f5ef-3807603.jpg" class="lozad post-image"src="https://api2.mubu.com/v3/document_image/17f04b1d-8f4a-4e8c-af4c-0ee49247f5ef-3807603.jpg"></p>
<p>我们可以看到传进来的el是Ast语法树，el.directives是el上的指令，在我们这里就是el-model的相关参数,然后赋值给变量dirs</p>
<p>往下看代码，for循环中有段代码：</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> gen <span class="token operator">=</span> state<span class="token punctuation">.</span>directives<span class="token punctuation">[</span>dir<span class="token punctuation">.</span>name<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>gen<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
  <span class="token comment">// compile-time directive that manipulates AST.</span>
  <span class="token comment">// returns true if it also needs a runtime counterpart.</span>
  needRuntime <span class="token operator">=</span> <span class="token operator">!</span><span class="token operator">!</span><span class="token function">gen</span><span class="token punctuation">(</span>el<span class="token punctuation">,</span> dir<span class="token punctuation">,</span> state<span class="token punctuation">.</span>warn<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>这里面的state.dirctives是什么呢？打个断点看一下，如下图：</p>
<p><img  srcset="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20300%20300'%3E%3C/svg%3E" data-src="https://api2.mubu.com/v3/document_image/3a1b4b1e-bd87-423d-9515-40ced534dcc0-3807603.jpg" class="lozad post-image"src="https://api2.mubu.com/v3/document_image/3a1b4b1e-bd87-423d-9515-40ced534dcc0-3807603.jpg"></p>
<p>我们可以看到<code>state.directives</code>里面包含了很多指令方法，model 就在其中，</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> gen <span class="token operator">=</span> state<span class="token punctuation">.</span>directives<span class="token punctuation">[</span>dir<span class="token punctuation">.</span>name<span class="token punctuation">]</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>

<p>其实就是等价于</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> gen <span class="token operator">=</span> state<span class="token punctuation">.</span>directives<span class="token punctuation">[</span>model<span class="token punctuation">]</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>

<p>所以代码中的变量 gen 得到的是<code>model()</code></p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript">needRuntime <span class="token operator">=</span> <span class="token operator">!</span><span class="token operator">!</span><span class="token function">gen</span><span class="token punctuation">(</span>el<span class="token punctuation">,</span> dir<span class="token punctuation">,</span> state<span class="token punctuation">.</span>warn<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>
<p>其实就是执行了<code>model()</code></p>
<h4 id="model"><a href="#model" class="headerlink" title="model"></a>model</h4><p>那我们再来看看model这个方法里面做了些什么事情，先上model的代码：</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">model</span> <span class="token punctuation">(</span><span class="token parameter">el<span class="token punctuation">,</span>dir<span class="token punctuation">,</span>_warn</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
  warn$<span class="token number">1</span> <span class="token operator">=</span> _warn<span class="token punctuation">;</span>
  <span class="token keyword">var</span> value <span class="token operator">=</span> dir<span class="token punctuation">.</span>value<span class="token punctuation">;</span>
  <span class="token keyword">var</span> modifiers <span class="token operator">=</span> dir<span class="token punctuation">.</span>modifiers<span class="token punctuation">;</span>
  <span class="token keyword">var</span> tag <span class="token operator">=</span> el<span class="token punctuation">.</span>tag<span class="token punctuation">;</span>
  <span class="token keyword">var</span> type <span class="token operator">=</span> el<span class="token punctuation">.</span>attrsMap<span class="token punctuation">.</span>type<span class="token punctuation">;</span>

  <span class="token punctuation">&#123;</span>
    <span class="token comment">// inputs with type="file" are read only and setting the input's</span>
    <span class="token comment">// value will throw an error.</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>tag <span class="token operator">===</span> <span class="token string">'input'</span> <span class="token operator">&amp;&amp;</span> type <span class="token operator">===</span> <span class="token string">'file'</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
      <span class="token function">warn$1</span><span class="token punctuation">(</span>
        <span class="token string">"&lt;"</span> <span class="token operator">+</span> <span class="token punctuation">(</span>el<span class="token punctuation">.</span>tag<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">" v-model=\""</span> <span class="token operator">+</span> value <span class="token operator">+</span> <span class="token string">"\" type=\"file\">:\n"</span> <span class="token operator">+</span>
        <span class="token string">"File inputs are read only. Use a v-on:change listener instead."</span><span class="token punctuation">,</span>
        el<span class="token punctuation">.</span>rawAttrsMap<span class="token punctuation">[</span><span class="token string">'v-model'</span><span class="token punctuation">]</span>
      <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
  <span class="token punctuation">&#125;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span>el<span class="token punctuation">.</span>component<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    <span class="token function">genComponentModel</span><span class="token punctuation">(</span>el<span class="token punctuation">,</span> value<span class="token punctuation">,</span> modifiers<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// component v-model doesn't need extra runtime</span>
    <span class="token keyword">return</span> <span class="token boolean">false</span>
  <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>tag <span class="token operator">===</span> <span class="token string">'select'</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    <span class="token function">genSelect</span><span class="token punctuation">(</span>el<span class="token punctuation">,</span> value<span class="token punctuation">,</span> modifiers<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>tag <span class="token operator">===</span> <span class="token string">'input'</span> <span class="token operator">&amp;&amp;</span> type <span class="token operator">===</span> <span class="token string">'checkbox'</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    <span class="token function">genCheckboxModel</span><span class="token punctuation">(</span>el<span class="token punctuation">,</span> value<span class="token punctuation">,</span> modifiers<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>tag <span class="token operator">===</span> <span class="token string">'input'</span> <span class="token operator">&amp;&amp;</span> type <span class="token operator">===</span> <span class="token string">'radio'</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    <span class="token function">genRadioModel</span><span class="token punctuation">(</span>el<span class="token punctuation">,</span> value<span class="token punctuation">,</span> modifiers<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>tag <span class="token operator">===</span> <span class="token string">'input'</span> <span class="token operator">||</span> tag <span class="token operator">===</span> <span class="token string">'textarea'</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    <span class="token function">genDefaultModel</span><span class="token punctuation">(</span>el<span class="token punctuation">,</span> value<span class="token punctuation">,</span> modifiers<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>config<span class="token punctuation">.</span><span class="token function">isReservedTag</span><span class="token punctuation">(</span>tag<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    <span class="token function">genComponentModel</span><span class="token punctuation">(</span>el<span class="token punctuation">,</span> value<span class="token punctuation">,</span> modifiers<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// component v-model doesn't need extra runtime</span>
    <span class="token keyword">return</span> <span class="token boolean">false</span>
  <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token punctuation">&#123;</span>
    <span class="token function">warn$1</span><span class="token punctuation">(</span>
      <span class="token string">"&lt;"</span> <span class="token operator">+</span> <span class="token punctuation">(</span>el<span class="token punctuation">.</span>tag<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">" v-model=\""</span> <span class="token operator">+</span> value <span class="token operator">+</span> <span class="token string">"\">: "</span> <span class="token operator">+</span>
      <span class="token string">"v-model is not supported on this element type. "</span> <span class="token operator">+</span>
      <span class="token string">'If you are working with contenteditable, it\'s recommended to '</span> <span class="token operator">+</span>
      <span class="token string">'wrap a library dedicated for that purpose inside a custom component.'</span><span class="token punctuation">,</span>
      el<span class="token punctuation">.</span>rawAttrsMap<span class="token punctuation">[</span><span class="token string">'v-model'</span><span class="token punctuation">]</span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">&#125;</span>

  <span class="token comment">// ensure runtime directive metadata</span>
  <span class="token keyword">return</span> <span class="token boolean">true</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>model 方法根据传入的参数对 tag 的类型进行判断，调用不同的处理逻辑，本 demo 中 tag 的类型为 input，所以会执行<code>genDefaultModel</code>方法</p>
<h4 id="genDefaultModel"><a href="#genDefaultModel" class="headerlink" title="genDefaultModel"></a>genDefaultModel</h4><pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">genDefaultModel</span> <span class="token punctuation">(</span><span class="token parameter">el<span class="token punctuation">,</span>value<span class="token punctuation">,</span>modifiers</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
  <span class="token keyword">var</span> type <span class="token operator">=</span> el<span class="token punctuation">.</span>attrsMap<span class="token punctuation">.</span>type<span class="token punctuation">;</span>
  <span class="token punctuation">&#123;</span>
    <span class="token keyword">var</span> value$<span class="token number">1</span> <span class="token operator">=</span> el<span class="token punctuation">.</span>attrsMap<span class="token punctuation">[</span><span class="token string">'v-bind:value'</span><span class="token punctuation">]</span> <span class="token operator">||</span> el<span class="token punctuation">.</span>attrsMap<span class="token punctuation">[</span><span class="token string">':value'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">var</span> typeBinding <span class="token operator">=</span> el<span class="token punctuation">.</span>attrsMap<span class="token punctuation">[</span><span class="token string">'v-bind:type'</span><span class="token punctuation">]</span> <span class="token operator">||</span> el<span class="token punctuation">.</span>attrsMap<span class="token punctuation">[</span><span class="token string">':type'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>value$<span class="token number">1</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>typeBinding<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
      <span class="token keyword">var</span> binding <span class="token operator">=</span> el<span class="token punctuation">.</span>attrsMap<span class="token punctuation">[</span><span class="token string">'v-bind:value'</span><span class="token punctuation">]</span> <span class="token operator">?</span> <span class="token string">'v-bind:value'</span> <span class="token operator">:</span> <span class="token string">':value'</span><span class="token punctuation">;</span>
      <span class="token function">warn$1</span><span class="token punctuation">(</span>
        binding <span class="token operator">+</span> <span class="token string">"=\""</span> <span class="token operator">+</span> value$<span class="token number">1</span> <span class="token operator">+</span> <span class="token string">"\" conflicts with v-model on the same element "</span> <span class="token operator">+</span>
        <span class="token string">'because the latter already expands to a value binding internally'</span><span class="token punctuation">,</span>
        el<span class="token punctuation">.</span>rawAttrsMap<span class="token punctuation">[</span>binding<span class="token punctuation">]</span>
      <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
  <span class="token punctuation">&#125;</span>

  <span class="token keyword">var</span> ref <span class="token operator">=</span> modifiers <span class="token operator">||</span> <span class="token punctuation">&#123;</span><span class="token punctuation">&#125;</span><span class="token punctuation">;</span>
  <span class="token keyword">var</span> lazy <span class="token operator">=</span> ref<span class="token punctuation">.</span>lazy<span class="token punctuation">;</span>
  <span class="token keyword">var</span> number <span class="token operator">=</span> ref<span class="token punctuation">.</span>number<span class="token punctuation">;</span>
  <span class="token keyword">var</span> trim <span class="token operator">=</span> ref<span class="token punctuation">.</span>trim<span class="token punctuation">;</span>
  <span class="token keyword">var</span> needCompositionGuard <span class="token operator">=</span> <span class="token operator">!</span>lazy <span class="token operator">&amp;&amp;</span> type <span class="token operator">!==</span> <span class="token string">'range'</span><span class="token punctuation">;</span>
  <span class="token keyword">var</span> event <span class="token operator">=</span> lazy
    <span class="token operator">?</span> <span class="token string">'change'</span>
    <span class="token operator">:</span> type <span class="token operator">===</span> <span class="token string">'range'</span>
      <span class="token operator">?</span> <span class="token constant">RANGE_TOKEN</span>
      <span class="token operator">:</span> <span class="token string">'input'</span><span class="token punctuation">;</span>

  <span class="token keyword">var</span> valueExpression <span class="token operator">=</span> <span class="token string">'$event.target.value'</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>trim<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    valueExpression <span class="token operator">=</span> <span class="token string">"$event.target.value.trim()"</span><span class="token punctuation">;</span>
  <span class="token punctuation">&#125;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>number<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    valueExpression <span class="token operator">=</span> <span class="token string">"_n("</span> <span class="token operator">+</span> valueExpression <span class="token operator">+</span> <span class="token string">")"</span><span class="token punctuation">;</span>
  <span class="token punctuation">&#125;</span>

  <span class="token keyword">var</span> code <span class="token operator">=</span> <span class="token function">genAssignmentCode</span><span class="token punctuation">(</span>value<span class="token punctuation">,</span> valueExpression<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>needCompositionGuard<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    code <span class="token operator">=</span> <span class="token string">"if($event.target.composing)return;"</span> <span class="token operator">+</span> code<span class="token punctuation">;</span>
  <span class="token punctuation">&#125;</span>

  <span class="token function">addProp</span><span class="token punctuation">(</span>el<span class="token punctuation">,</span> <span class="token string">'value'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token string">"("</span> <span class="token operator">+</span> value <span class="token operator">+</span> <span class="token string">")"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">addHandler</span><span class="token punctuation">(</span>el<span class="token punctuation">,</span> event<span class="token punctuation">,</span> code<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>trim <span class="token operator">||</span> number<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    <span class="token function">addHandler</span><span class="token punctuation">(</span>el<span class="token punctuation">,</span> <span class="token string">'blur'</span><span class="token punctuation">,</span> <span class="token string">'$forceUpdate()'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>我们对<code>genDefaultModel()</code>中的代码进行分块解析，首先看下面这段代码：</p>
<p>是否同时具有指令<code>v-model</code>和<code>v-bind</code></p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> value$<span class="token number">1</span> <span class="token operator">=</span> el<span class="token punctuation">.</span>attrsMap<span class="token punctuation">[</span><span class="token string">'v-bind:value'</span><span class="token punctuation">]</span> <span class="token operator">||</span> el<span class="token punctuation">.</span>attrsMap<span class="token punctuation">[</span><span class="token string">':value'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> typeBinding <span class="token operator">=</span> el<span class="token punctuation">.</span>attrsMap<span class="token punctuation">[</span><span class="token string">'v-bind:type'</span><span class="token punctuation">]</span> <span class="token operator">||</span> el<span class="token punctuation">.</span>attrsMap<span class="token punctuation">[</span><span class="token string">':type'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>value$<span class="token number">1</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>typeBinding<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
  <span class="token keyword">var</span> binding <span class="token operator">=</span> el<span class="token punctuation">.</span>attrsMap<span class="token punctuation">[</span><span class="token string">'v-bind:value'</span><span class="token punctuation">]</span> <span class="token operator">?</span> <span class="token string">'v-bind:value'</span> <span class="token operator">:</span> <span class="token string">':value'</span><span class="token punctuation">;</span>
  <span class="token function">warn$1</span><span class="token punctuation">(</span>
    binding <span class="token operator">+</span> <span class="token string">"=\""</span> <span class="token operator">+</span> value$<span class="token number">1</span> <span class="token operator">+</span> <span class="token string">"\" conflicts with v-model on the same element "</span> <span class="token operator">+</span>
    <span class="token string">'because the latter already expands to a value binding internally'</span><span class="token punctuation">,</span>
    el<span class="token punctuation">.</span>rawAttrsMap<span class="token punctuation">[</span>binding<span class="token punctuation">]</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>这块代码其实就是解释表单元素是否同时有指令<code>v-model</code>和<code>v-bind</code></p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> ref <span class="token operator">=</span> modifiers <span class="token operator">||</span> <span class="token punctuation">&#123;</span><span class="token punctuation">&#125;</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> lazy <span class="token operator">=</span> ref<span class="token punctuation">.</span>lazy<span class="token punctuation">;</span>
<span class="token keyword">var</span> number <span class="token operator">=</span> ref<span class="token punctuation">.</span>number<span class="token punctuation">;</span>
<span class="token keyword">var</span> trim <span class="token operator">=</span> ref<span class="token punctuation">.</span>trim<span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre>
<p>修饰符: 这段代码就是获取修饰符 lazy, number 及 trim</p>
<ol>
<li>.lazy 取代 input 监听 change 事件</li>
<li>.number 输入字符串转为数字</li>
<li>.trim 输入首尾空格过滤</li>
</ol>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> needCompositionGuard <span class="token operator">=</span> <span class="token operator">!</span>lazy <span class="token operator">&amp;&amp;</span> type <span class="token operator">!==</span> <span class="token string">'range'</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>
<p>这里的<code>needCompositionGuard</code>后面再说有什么用，现在只用知道默认是 true 就行了</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> event <span class="token operator">=</span> lazy
  <span class="token operator">?</span> <span class="token string">'change'</span>
  <span class="token operator">:</span> type <span class="token operator">===</span> <span class="token string">'range'</span>
    <span class="token operator">?</span> <span class="token constant">RANGE_TOKEN</span>
    <span class="token operator">:</span> <span class="token string">'input'</span><span class="token punctuation">;</span>

<span class="token keyword">var</span> valueExpression <span class="token operator">=</span> <span class="token string">'$event.target.value'</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>trim<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
  valueExpression <span class="token operator">=</span> <span class="token string">"$event.target.value.trim()"</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>number<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
  valueExpression <span class="token operator">=</span> <span class="token string">"_n("</span> <span class="token operator">+</span> valueExpression <span class="token operator">+</span> <span class="token string">")"</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>上面这段代码中，<code>event = &#39;input&#39;</code>,定义变量 valueExpression，修饰符 trim 和 number 在我们这个 demo 中默认都没有，所以跳过往下看</p>
<h4 id="genAssignmentCode"><a href="#genAssignmentCode" class="headerlink" title="genAssignmentCode"></a>genAssignmentCode</h4><pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> code <span class="token operator">=</span> <span class="token function">genAssignmentCode</span><span class="token punctuation">(</span>value<span class="token punctuation">,</span> valueExpression<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>needCompositionGuard<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
  code <span class="token operator">=</span> <span class="token string">"if($event.target.composing)return;"</span> <span class="token operator">+</span> code<span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre>

<p>这里涉及到一个函数 genAssignmentCode,上源码：</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">genAssignmentCode</span> <span class="token punctuation">(</span>
  <span class="token parameter">value<span class="token punctuation">,</span>
  assignment</span>
<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
  <span class="token keyword">var</span> res <span class="token operator">=</span> <span class="token function">parseModel</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>res<span class="token punctuation">.</span>key <span class="token operator">===</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    <span class="token keyword">return</span> <span class="token punctuation">(</span>value <span class="token operator">+</span> <span class="token string">"="</span> <span class="token operator">+</span> assignment<span class="token punctuation">)</span>
  <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token punctuation">&#123;</span>
    <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token string">"$set("</span> <span class="token operator">+</span> <span class="token punctuation">(</span>res<span class="token punctuation">.</span>exp<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">", "</span> <span class="token operator">+</span> <span class="token punctuation">(</span>res<span class="token punctuation">.</span>key<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">", "</span> <span class="token operator">+</span> assignment <span class="token operator">+</span> <span class="token string">")"</span><span class="token punctuation">)</span>
  <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>这段代码是生成v-model绑定的value的值，看到这段代码，我们就知道离真相不远了，因为我们看到了$set()。现在我们通过断点具体分析下，如下图：</p>
<p><img  srcset="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20300%20300'%3E%3C/svg%3E" data-src="https://api2.mubu.com/v3/document_image/b366198f-7c22-4cc3-8972-2a9f59661a23-3807603.jpg" class="lozad post-image"src="https://api2.mubu.com/v3/document_image/b366198f-7c22-4cc3-8972-2a9f59661a23-3807603.jpg"></p>
<p>通过断点我们可以很清楚的看到我们先执行<code>parseModel(&#39;info.message&#39;)</code>获取到一个对象 res，由于我们的 demo 中绑定的值是路径形式的对象，即 info.message，所以此时 res 通过 parseModel 解析出来就是<code>&#123;exp: &quot;info&quot;, key: &quot;message&quot;&#125;</code>。那下面的判断就进入 else，即：</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token string">"$set("</span> <span class="token operator">+</span> <span class="token punctuation">(</span>res<span class="token punctuation">.</span>exp<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">", "</span> <span class="token operator">+</span> <span class="token punctuation">(</span>res<span class="token punctuation">.</span>key<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">", "</span> <span class="token operator">+</span> assignment <span class="token operator">+</span> <span class="token string">")"</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>

<p>回到上面的getDefaultModel()中</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> code <span class="token operator">=</span> <span class="token function">genAssignmentCode</span><span class="token punctuation">(</span>value<span class="token punctuation">,</span> valueExpression<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>needCompositionGuard<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
  code <span class="token operator">=</span> <span class="token string">"if($event.target.composing)return;"</span> <span class="token operator">+</span> code<span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre>

<p>此时 code 获取到<code>genAssignmentCode()</code>返回的字符串值<code>&quot;$set(info, &quot;message&quot;, $event.target.value)&quot;</code></p>
<h4 id="event-target-composing"><a href="#event-target-composing" class="headerlink" title="$event.target.composing"></a>$event.target.composing</h4><p>上面我说的到变量<code>needCompositionGuard = true</code>，经过拼接，最终code = <code>“if($event.target.composing)return;$set(info, &quot;message&quot;, $event.target.value)”</code></p>
<p>这里的<code>$event.target.composing</code>有什么用呢？其实就是用于判断此次 input 事件是否是 IME 构成触发的，如果是 IME 构成，直接 return。IME 是输入法编辑器(Input Method Editor) 的英文缩写，IME 构成指我们在输入文字时，处于未确认状态的文字。如图：</p>
<p><img  srcset="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20300%20300'%3E%3C/svg%3E" data-src="https://api2.mubu.com/v3/document_image/1d9ffc36-bd0e-47bb-9989-1668765c5aa6-3807603.jpg" class="lozad post-image"src="https://api2.mubu.com/v3/document_image/1d9ffc36-bd0e-47bb-9989-1668765c5aa6-3807603.jpg"></p>
<p>带下划线的ceshi就属于IME构成，它会同样会触发input事件，但不会触发v-model更新数据。</p>
<p>继续往下看</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token function">addProp</span><span class="token punctuation">(</span>el<span class="token punctuation">,</span> <span class="token string">'value'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token string">"("</span> <span class="token operator">+</span> value <span class="token operator">+</span> <span class="token string">")"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">addHandler</span><span class="token punctuation">(</span>el<span class="token punctuation">,</span> event<span class="token punctuation">,</span> code<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>trim <span class="token operator">||</span> number<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
  <span class="token function">addHandler</span><span class="token punctuation">(</span>el<span class="token punctuation">,</span> <span class="token string">'blur'</span><span class="token punctuation">,</span> <span class="token string">'$forceUpdate()'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<h4 id="addProp"><a href="#addProp" class="headerlink" title="addProp"></a>addProp</h4><p>先说下<code>addProp(el, &#39;value&#39;, (&quot;(&quot; + value + &quot;)&quot;))，</code></p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">addProp</span> <span class="token punctuation">(</span><span class="token parameter">el<span class="token punctuation">,</span> name<span class="token punctuation">,</span> value<span class="token punctuation">,</span> range<span class="token punctuation">,</span> dynamic</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
  <span class="token punctuation">(</span>el<span class="token punctuation">.</span>props <span class="token operator">||</span> <span class="token punctuation">(</span>el<span class="token punctuation">.</span>props <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token function">rangeSetItem</span><span class="token punctuation">(</span><span class="token punctuation">&#123;</span> name<span class="token operator">:</span> name<span class="token punctuation">,</span> value<span class="token operator">:</span> value<span class="token punctuation">,</span> dynamic<span class="token operator">:</span> dynamic <span class="token punctuation">&#125;</span><span class="token punctuation">,</span> range<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  el<span class="token punctuation">.</span>plain <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre>

<p>照常打个断点看下：如下图</p>
<p><img  srcset="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20300%20300'%3E%3C/svg%3E" data-src="https://api2.mubu.com/v3/document_image/ec580c4e-2912-4584-9111-cd1fd6cb10ef-3807603.jpg" class="lozad post-image"src="https://api2.mubu.com/v3/document_image/ec580c4e-2912-4584-9111-cd1fd6cb10ef-3807603.jpg"></p>
<p>可以看到此方法的功能为给 el 添加 props，首先判断 el 上有没有 props，如果没有的话创建 props 并赋值为一个空数组，随后拼接对象并推到 props 中，代码在此 demo 中相当于<code>push&#123;name: &quot;value&quot;, value: &quot;(info.message)&quot;&#125;</code></p>
<p>如果一直往下追，可以看到这个方法其实是在 input 输入框上绑定了 value，对照我们的 demo 来看，就是将&lt;input v-model=”info.message” type=”text”&gt;变成&lt;input v-bind:value=”info.message” type=”text”&gt;</p>
<h4 id="addHandler"><a href="#addHandler" class="headerlink" title="addHandler"></a>addHandler</h4><p>同样的，addHandler()相当于在input上绑定了input事件，最终我们demo的模版就会被编译成</p>
<pre class="line-numbers language-html" data-language="html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name"><span class="token namespace">v-bind:</span>value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>info.message<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">v-on:</span>input</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>info.message=$event.target.value<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>

<h4 id="render"><a href="#render" class="headerlink" title="render"></a>render</h4><p>后续再根据一些指令拼接，我们最终的到的render如下：</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">with</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
  <span class="token keyword">return</span> <span class="token function">_c</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">,</span> <span class="token punctuation">&#123;</span>
    attrs<span class="token operator">:</span> <span class="token punctuation">&#123;</span>
      <span class="token string">"id"</span><span class="token operator">:</span> <span class="token string">"app-2"</span>
    <span class="token punctuation">&#125;</span>
  <span class="token punctuation">&#125;</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token function">_c</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token function">_v</span><span class="token punctuation">(</span><span class="token function">_s</span><span class="token punctuation">(</span>info<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">_v</span><span class="token punctuation">(</span><span class="token string">" "</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">_c</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token function">_c</span><span class="token punctuation">(</span><span class="token string">'input'</span><span class="token punctuation">,</span> <span class="token punctuation">&#123;</span>
    directives<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">&#123;</span>
      name<span class="token operator">:</span> <span class="token string">"model"</span><span class="token punctuation">,</span>
      rawName<span class="token operator">:</span> <span class="token string">"v-model"</span><span class="token punctuation">,</span>
      value<span class="token operator">:</span> <span class="token punctuation">(</span>info<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">,</span>
      expression<span class="token operator">:</span> <span class="token string">"info.message"</span>
    <span class="token punctuation">&#125;</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    attrs<span class="token operator">:</span> <span class="token punctuation">&#123;</span>
      <span class="token string">"type"</span><span class="token operator">:</span> <span class="token string">"text"</span>
    <span class="token punctuation">&#125;</span><span class="token punctuation">,</span>
    domProps<span class="token operator">:</span> <span class="token punctuation">&#123;</span>
      <span class="token string">"value"</span><span class="token operator">:</span> <span class="token punctuation">(</span>info<span class="token punctuation">.</span>message<span class="token punctuation">)</span>
    <span class="token punctuation">&#125;</span><span class="token punctuation">,</span>
    on<span class="token operator">:</span> <span class="token punctuation">&#123;</span>
      <span class="token string">"input"</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">$event</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
          <span class="token keyword">if</span> <span class="token punctuation">(</span>$event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>composing<span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>
          <span class="token function">$set</span><span class="token punctuation">(</span>info<span class="token punctuation">,</span> <span class="token string">"message"</span><span class="token punctuation">,</span> $event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span>
      <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span>
  <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">_v</span><span class="token punctuation">(</span><span class="token string">" "</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">_c</span><span class="token punctuation">(</span><span class="token string">'button'</span><span class="token punctuation">,</span> <span class="token punctuation">&#123;</span>
    on<span class="token operator">:</span> <span class="token punctuation">&#123;</span>
        <span class="token string">"click"</span><span class="token operator">:</span> change
    <span class="token punctuation">&#125;</span>
  <span class="token punctuation">&#125;</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token function">_v</span><span class="token punctuation">(</span><span class="token string">"click"</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>最后通过<code>createFunction()</code>把 render 代码串通过 new Function 的方式转换成可执行的函数，赋值给 <code>vm.options.render</code>，这样当组件通过<code>vm._render</code>的时候，就会执行这个 render 函数</p>
<p>至此，针对表单元素上的 v-model 指令从开始编译到最终生成<code>render()</code>并执行的过程就讲解完了，我们验证了在编译阶段，v-model 会在监听到 input 事件时对我们绑定的 value 进行<code>Vue.$set()</code>操作</p>
<p>还记得我们上面说的对 demo 第二种操作情况么？先进行 click 操作赋值，那 v-model 中的<code>Vue.$set()</code>操作似乎没有作用了。我们当时猜测的是<code>Vue.$set()</code>底层源码中有应该是会判断 message 属性是否一开始就在 info 中，如果存在就只是进行单纯的赋值，不存在的话在进行响应式操作，绑定 getter 和 setter</p>
<p>现在我们就去<code>Vue.$set()</code>中看一下</p>
<h4 id="set"><a href="#set" class="headerlink" title="set"></a>set</h4><p>先上代码：</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">/**
   * Set a property on an object. Adds the new property and
   * triggers change notification if the property doesn't
   * already exist.
   */</span>
  <span class="token keyword">function</span> <span class="token function">set</span> <span class="token punctuation">(</span><span class="token parameter">target<span class="token punctuation">,</span> key<span class="token punctuation">,</span> val</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isUndef</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token function">isPrimitive</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span>
  <span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    <span class="token function">warn</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token string">"Cannot set reactive property on undefined, null, or primitive value: "</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">&#125;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token function">isValidArrayIndex</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    target<span class="token punctuation">.</span>length <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">max</span><span class="token punctuation">(</span>target<span class="token punctuation">.</span>length<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">;</span>
    target<span class="token punctuation">.</span><span class="token function">splice</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> val<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> val
  <span class="token punctuation">&#125;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>key <span class="token keyword">in</span> target <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span><span class="token punctuation">(</span>key <span class="token keyword">in</span> <span class="token class-name">Object</span><span class="token punctuation">.</span>prototype<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    target<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> val<span class="token punctuation">;</span>
    <span class="token keyword">return</span> val
  <span class="token punctuation">&#125;</span>
  <span class="token keyword">var</span> ob <span class="token operator">=</span> <span class="token punctuation">(</span>target<span class="token punctuation">)</span><span class="token punctuation">.</span>__ob__<span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>target<span class="token punctuation">.</span>_isVue <span class="token operator">||</span> <span class="token punctuation">(</span>ob <span class="token operator">&amp;&amp;</span> ob<span class="token punctuation">.</span>vmCount<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    <span class="token function">warn</span><span class="token punctuation">(</span>
      <span class="token string">'Avoid adding reactive properties to a Vue instance or its root $data '</span> <span class="token operator">+</span>
      <span class="token string">'at runtime - declare it upfront in the data option.'</span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> val
  <span class="token punctuation">&#125;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>ob<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    target<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> val<span class="token punctuation">;</span>
    <span class="token keyword">return</span> val
  <span class="token punctuation">&#125;</span>
  <span class="token function">defineReactive$$1</span><span class="token punctuation">(</span>ob<span class="token punctuation">.</span>value<span class="token punctuation">,</span> key<span class="token punctuation">,</span> val<span class="token punctuation">)</span><span class="token punctuation">;</span>
  ob<span class="token punctuation">.</span>dep<span class="token punctuation">.</span><span class="token function">notify</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> val
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>看到这句代码了么？这就是证据，验证我们猜想的证据</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">if</span> <span class="token punctuation">(</span>key <span class="token keyword">in</span> target <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span><span class="token punctuation">(</span>key <span class="token keyword">in</span> <span class="token class-name">Object</span><span class="token punctuation">.</span>prototype<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
  target<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> val<span class="token punctuation">;</span>
  <span class="token keyword">return</span> val
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre>

<h4 id="验证猜想"><a href="#验证猜想" class="headerlink" title="验证猜想"></a>验证猜想</h4><p>当我们首先点击 click 的时候，执行<code>this.info.message = &#39;hello world&#39;</code>,此时 info 对象中新增了一个 message 属性。当我们在 input 框中输入值并触发<code>Vue.$set()</code>时，key in target为true，并且 message 又不是 Object 原型上的属性，所以<code>!(key in Object.prototype)</code>也为 true，此时 message 属性并不是响应式属性，没有绑定 setter，所以仅仅进行了单纯的赋值操作。</p>
<p>而当我们一进页面首次在 input 中执行输入操作时，根据上面我们的分析 input 框监听到了 input 事件，先执行了<code>Vue.$set()</code>操作，因为时首次，所以 info 中还没有 message 属性，所以上面的key in target 为 false，跳过了赋值操作，到了下面的</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token function">defineReactive$$1</span><span class="token punctuation">(</span>ob<span class="token punctuation">.</span>value<span class="token punctuation">,</span> key<span class="token punctuation">,</span> val<span class="token punctuation">)</span><span class="token punctuation">;</span>
ob<span class="token punctuation">.</span>dep<span class="token punctuation">.</span><span class="token function">notify</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>

<p>这个 defineReactive 的作用就是为 message 绑定了<code>getter()</code>和<code>setter()</code>，之后再对 message 的赋值操作都会直接进入自身绑定的 setter 中进行响应式操作</p>
<h2 id="一个意外的发现"><a href="#一个意外的发现" class="headerlink" title="一个意外的发现"></a>一个意外的发现</h2><p>我突然奇想把 vue 的版本换到了 2.3.0，发现 v-model 不能对 demo 中的 message 属性实现响应化，跑去看了下 vue 更新日志，发现在 2.5.0 版本中，有这么一句话<br><code>now creates non-existent properties as reactive (non-recursive) e1da0d5, closes #5932 (See reasoning behind this change)</code><br>上面这句话的意思是从 2.5.0 版本开始支持将不存在的属性响应化，非递归的。<br>因为 message 属性一开始在info中并没有定义，在 2.3.0 中，还不支持将不存在的属性响应化的操作，所以对 demo 无效</p>
<h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>到这里，我们这篇文章就结束了 里面有一些细节如果大家有兴趣的话可以自己再去深究一下。有时候很小的一个问题，背后牵扯到的知识点也是很多的，尽量把每个不懂背后的逻辑搞清楚，才能尽快的成为你想成为的人</p>
<h2 id="参考链接"><a href="#参考链接" class="headerlink" title="参考链接"></a>参考链接</h2><p><a target="_blank" rel="noopener" href="https://segmentfault.com/a/1190000021039085">v-model源码解析(超详细)</a><br><a target="_blank" rel="noopener" href="https://segmentfault.com/a/1190000015848976#articleHeader0">Vue源码解读之v-model</a><br><a target="_blank" rel="noopener" href="https://blog.csdn.net/fabulous1111/article/details/85265503">[Vue源码分析] v-model实现原理</a></p>

  </div>
  <div>
    
  </div>
</article>
<div class="nav">
  
    <div class="nav-item-prev">
      <a 
        href="/2021/08/16/TODO/" 
        class="nav-link">
        <i class="iconfont icon-left nav-prev-icon"></i>
        <div>
          <div class="nav-label">上一篇</div>
          
            <div class="nav-title">TODO </div>
          
        </div>
      </a>
    </div>
  
  
    <div class="nav-item-next">
      <a 
        href="/2021/08/11/javascriptTypesAndTypeJudgment/" 
        class="nav-link">
        <div>
          <div class="nav-label">下一篇</div>
          
            <div class="nav-title">Javascript类型与类型判断 </div>
          
        </div>
        <i class="iconfont icon-right nav-next-icon"></i>
      </a>
    </div>
  
</div>

<div 
  class="card card-content toc-card" 
  id="mobiletoc">
  <div class="toc-header">
  <i 
    class="iconfont icon-menu" 
    style="padding-right: 2px;">
  </i>目录
</div>
<ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%8A%9B%E5%87%BA%E9%97%AE%E9%A2%98"><span class="toc-text">抛出问题</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%97%AE%E9%A2%98%E9%87%8D%E7%8E%B0%E6%AD%A5%E9%AA%A4"><span class="toc-text">问题重现步骤</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%97%AE%E9%A2%98%E5%BC%95%E5%8F%91%E7%9A%84%E7%8C%9C%E6%83%B3"><span class="toc-text">问题引发的猜想</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%8E%A2%E7%B4%A2%E7%9C%9F%E7%9B%B8-%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90"><span class="toc-text">探索真相-源码分析</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#v-model%E5%AE%9E%E7%8E%B0%E6%9C%BA%E5%88%B6"><span class="toc-text">v-model实现机制</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#v-model%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86"><span class="toc-text">v-model实现原理</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%BC%96%E8%AF%91"><span class="toc-text">编译</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#genDirectives"><span class="toc-text">genDirectives</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#model"><span class="toc-text">model</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#genDefaultModel"><span class="toc-text">genDefaultModel</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#genAssignmentCode"><span class="toc-text">genAssignmentCode</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#event-target-composing"><span class="toc-text">$event.target.composing</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#addProp"><span class="toc-text">addProp</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#addHandler"><span class="toc-text">addHandler</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#render"><span class="toc-text">render</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#set"><span class="toc-text">set</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%AA%8C%E8%AF%81%E7%8C%9C%E6%83%B3"><span class="toc-text">验证猜想</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%80%E4%B8%AA%E6%84%8F%E5%A4%96%E7%9A%84%E5%8F%91%E7%8E%B0"><span class="toc-text">一个意外的发现</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%80%BB%E7%BB%93"><span class="toc-text">总结</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8F%82%E8%80%83%E9%93%BE%E6%8E%A5"><span class="toc-text">参考链接</span></a></li></ol>
</div></main>
            <aside class="left-column">
              
              <div class="card card-author">
                
  <img 
    src="https://api2.mubu.com/v3/photo/654b368e-b847-4122-982c-86d90b3f5275.jpg" 
    class="author-img" 
    alt="author avatar">

<p class="author-name">霜序廿</p>
<p class="author-description">无限进步</p>
<div class="author-message">
  <a 
    class="author-posts-count" 
    href="/archives">
    <span>253</span>
    <span>文章</span>
  </a>
  <a 
    class="author-categories-count" 
    href="/categories">
    <span>6</span>
    <span>分类</span>
  </a>
  <a 
    class="author-tags-count" 
    href="/tags">
    <span>51</span>
    <span>标签</span>
  </a>
</div>

  <div class="author-card-society">
    
      <div class="author-card-society-icon">
        <a target="_blank" rel="noopener" href="https://github.com/shuangxunian">
          <i class="iconfont icon-github society-icon"></i>
        </a>
      </div>
    
      <div class="author-card-society-icon">
        <a target="_blank" rel="noopener" href="https://space.bilibili.com/391117803">
          <i class="iconfont icon-bilibili society-icon"></i>
        </a>
      </div>
    
  </div>

              </div>
               <div class="sticky-tablet">
  
  
    <article class="display-when-two-columns spacer">
      <div class="card card-content toc-card">
        <div class="toc-header">
  <i 
    class="iconfont icon-menu" 
    style="padding-right: 2px;">
  </i>目录
</div>
<ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%8A%9B%E5%87%BA%E9%97%AE%E9%A2%98"><span class="toc-text">抛出问题</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%97%AE%E9%A2%98%E9%87%8D%E7%8E%B0%E6%AD%A5%E9%AA%A4"><span class="toc-text">问题重现步骤</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%97%AE%E9%A2%98%E5%BC%95%E5%8F%91%E7%9A%84%E7%8C%9C%E6%83%B3"><span class="toc-text">问题引发的猜想</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%8E%A2%E7%B4%A2%E7%9C%9F%E7%9B%B8-%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90"><span class="toc-text">探索真相-源码分析</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#v-model%E5%AE%9E%E7%8E%B0%E6%9C%BA%E5%88%B6"><span class="toc-text">v-model实现机制</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#v-model%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86"><span class="toc-text">v-model实现原理</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%BC%96%E8%AF%91"><span class="toc-text">编译</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#genDirectives"><span class="toc-text">genDirectives</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#model"><span class="toc-text">model</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#genDefaultModel"><span class="toc-text">genDefaultModel</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#genAssignmentCode"><span class="toc-text">genAssignmentCode</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#event-target-composing"><span class="toc-text">$event.target.composing</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#addProp"><span class="toc-text">addProp</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#addHandler"><span class="toc-text">addHandler</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#render"><span class="toc-text">render</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#set"><span class="toc-text">set</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%AA%8C%E8%AF%81%E7%8C%9C%E6%83%B3"><span class="toc-text">验证猜想</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%80%E4%B8%AA%E6%84%8F%E5%A4%96%E7%9A%84%E5%8F%91%E7%8E%B0"><span class="toc-text">一个意外的发现</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%80%BB%E7%BB%93"><span class="toc-text">总结</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8F%82%E8%80%83%E9%93%BE%E6%8E%A5"><span class="toc-text">参考链接</span></a></li></ol>
      </div>
    </article>
  
  
  <article class="card card-content categories-widget">
    <div class="categories-card">
  <div class="categories-header">
    <i 
      class="iconfont icon-fenlei" 
      style="padding-right: 2px;">
    </i>分类
  </div>
  <div class="categories-list">
    
      <a href="/categories/%E6%8A%80%E6%9C%AF%E6%96%87%E7%AB%A0/">
        <div class="categories-list-item">
          技术文章
          <span class="categories-list-item-badge">218</span>
        </div>
      </a>
    
      <a href="/categories/%E5%85%B6%E4%BB%96/">
        <div class="categories-list-item">
          其他
          <span class="categories-list-item-badge">16</span>
        </div>
      </a>
    
      <a href="/categories/%E6%97%85%E6%B8%B8/">
        <div class="categories-list-item">
          旅游
          <span class="categories-list-item-badge">1</span>
        </div>
      </a>
    
      <a href="/categories/%E7%AE%97%E6%B3%95/">
        <div class="categories-list-item">
          算法
          <span class="categories-list-item-badge">8</span>
        </div>
      </a>
    
      <a href="/categories/%E8%80%83%E8%AF%95/">
        <div class="categories-list-item">
          考试
          <span class="categories-list-item-badge">8</span>
        </div>
      </a>
    
      <a href="/categories/%E9%98%85%E8%AF%BB/">
        <div class="categories-list-item">
          阅读
          <span class="categories-list-item-badge">1</span>
        </div>
      </a>
    
  </div>
</div>
  </article>
  
  <article class="card card-content tags-widget">
    <div class="tags-card">
  <div class="tags-header">
    <i 
      class="iconfont icon-biaoqian" 
      style="padding-right: 2px;">
    </i>热门标签
  </div>
  <div class="tags-list">
    
      <a 
        href="/tags/js/" 
        title="js">
        <div class="tags-list-item">js</div>
      </a>
    
      <a 
        href="/tags/vue/" 
        title="vue">
        <div class="tags-list-item">vue</div>
      </a>
    
      <a 
        href="/tags/%E9%9D%A2%E8%AF%95/" 
        title="面试">
        <div class="tags-list-item">面试</div>
      </a>
    
      <a 
        href="/tags/css/" 
        title="css">
        <div class="tags-list-item">css</div>
      </a>
    
      <a 
        href="/tags/%E7%BD%91%E7%BB%9C/" 
        title="网络">
        <div class="tags-list-item">网络</div>
      </a>
    
      <a 
        href="/tags/%E5%85%B6%E4%BB%96/" 
        title="其他">
        <div class="tags-list-item">其他</div>
      </a>
    
      <a 
        href="/tags/%E7%AE%97%E6%B3%95/" 
        title="算法">
        <div class="tags-list-item">算法</div>
      </a>
    
      <a 
        href="/tags/%E6%B5%8F%E8%A7%88%E5%99%A8/" 
        title="浏览器">
        <div class="tags-list-item">浏览器</div>
      </a>
    
      <a 
        href="/tags/html/" 
        title="html">
        <div class="tags-list-item">html</div>
      </a>
    
      <a 
        href="/tags/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/" 
        title="操作系统">
        <div class="tags-list-item">操作系统</div>
      </a>
    
      <a 
        href="/tags/%E8%80%83%E8%AF%95/" 
        title="考试">
        <div class="tags-list-item">考试</div>
      </a>
    
      <a 
        href="/tags/%E8%BD%AF%E5%AE%9E%E5%8A%9B/" 
        title="软实力">
        <div class="tags-list-item">软实力</div>
      </a>
    
      <a 
        href="/tags/DOM/" 
        title="DOM">
        <div class="tags-list-item">DOM</div>
      </a>
    
      <a 
        href="/tags/%E8%BD%AE%E5%AD%90/" 
        title="轮子">
        <div class="tags-list-item">轮子</div>
      </a>
    
      <a 
        href="/tags/%E7%BD%91%E7%BB%9C%E5%8E%9F%E7%90%86/" 
        title="网络原理">
        <div class="tags-list-item">网络原理</div>
      </a>
    
      <a 
        href="/tags/debug/" 
        title="debug">
        <div class="tags-list-item">debug</div>
      </a>
    
  </div>
</div>
  </article>
  
  
</div>
            </aside>
            <aside class="right-column">
              <div class="sticky-widescreen">
  
  
    <article class="card card-content toc-card">
      <div class="toc-header">
  <i 
    class="iconfont icon-menu" 
    style="padding-right: 2px;">
  </i>目录
</div>
<ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%8A%9B%E5%87%BA%E9%97%AE%E9%A2%98"><span class="toc-text">抛出问题</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%97%AE%E9%A2%98%E9%87%8D%E7%8E%B0%E6%AD%A5%E9%AA%A4"><span class="toc-text">问题重现步骤</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%97%AE%E9%A2%98%E5%BC%95%E5%8F%91%E7%9A%84%E7%8C%9C%E6%83%B3"><span class="toc-text">问题引发的猜想</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%8E%A2%E7%B4%A2%E7%9C%9F%E7%9B%B8-%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90"><span class="toc-text">探索真相-源码分析</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#v-model%E5%AE%9E%E7%8E%B0%E6%9C%BA%E5%88%B6"><span class="toc-text">v-model实现机制</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#v-model%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86"><span class="toc-text">v-model实现原理</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%BC%96%E8%AF%91"><span class="toc-text">编译</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#genDirectives"><span class="toc-text">genDirectives</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#model"><span class="toc-text">model</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#genDefaultModel"><span class="toc-text">genDefaultModel</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#genAssignmentCode"><span class="toc-text">genAssignmentCode</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#event-target-composing"><span class="toc-text">$event.target.composing</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#addProp"><span class="toc-text">addProp</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#addHandler"><span class="toc-text">addHandler</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#render"><span class="toc-text">render</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#set"><span class="toc-text">set</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%AA%8C%E8%AF%81%E7%8C%9C%E6%83%B3"><span class="toc-text">验证猜想</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%80%E4%B8%AA%E6%84%8F%E5%A4%96%E7%9A%84%E5%8F%91%E7%8E%B0"><span class="toc-text">一个意外的发现</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%80%BB%E7%BB%93"><span class="toc-text">总结</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8F%82%E8%80%83%E9%93%BE%E6%8E%A5"><span class="toc-text">参考链接</span></a></li></ol>
    </article>
  
  
  <article class="card card-content">
    <div class="recent-posts-card">
  <div class="recent-posts-header">
    <i 
      class="iconfont icon-wenzhang_huaban" 
      style="padding-right: 2px;">
    </i>最近文章
  </div>
  <div class="recent-posts-list">
    
      <div class="recent-posts-item">
        <div class="recent-posts-item-title">2022-05-01</div>
        <a href="/2022/05/01/typescriptHome/"><div class="recent-posts-item-content">typescript</div></a>
      </div>
    
      <div class="recent-posts-item">
        <div class="recent-posts-item-title">2022-01-15</div>
        <a href="/2022/01/15/javaScriptTheVariousWaysAndAdvantagesAndDisadvantagesOfDeepInheritance/"><div class="recent-posts-item-content">JavaScript深入之继承的多种方式和优缺点</div></a>
      </div>
    
      <div class="recent-posts-item">
        <div class="recent-posts-item-title">2022-01-15</div>
        <a href="/2022/01/15/javaScriptGoFromPrototypeToPrototypeChain/"><div class="recent-posts-item-content">JavaScript深入之从原型到原型链</div></a>
      </div>
    
      <div class="recent-posts-item">
        <div class="recent-posts-item-title">2022-01-15</div>
        <a href="/2022/01/15/javaScriptMemoryLeakTutorial/"><div class="recent-posts-item-content">JavaScript 内存泄漏教程</div></a>
      </div>
    
  </div>
</div>
  </article>
  
  
  
  <article class="card card-content">
    <div class="recent-posts-card">
  <div class="recent-posts-header">
    关注嘉然！顿顿解馋！
  </div>
  <div class="recent-posts-list">
    
      <img 
        src="https://api2.mubu.com/v3/document_image/2697c6ae-10ee-41a3-9099-304bdb252d31-3807603.jpg" 
        class="myadd-img" 
        alt="author avatar">
    
  </div>
</div>
  </article>
</div>
            </aside>
          </div>
        </div>
      </div>
    </div>
     
    <footer class="footer">
  <div class="footer-container">
    <div>
      <div class="footer-dsc">
        <span>
          Copyright ©
          
            2020 -
          
          2022
        </span>
        &nbsp;
        <a 
          href="/" 
          class="footer-link">
          霜序廿的个人网站
        </a>
      </div>
    </div>

    
      <div class="footer-dsc">
        
          Powered by
          <a 
            href="https://hexo.io/" 
            class="footer-link" 
            target="_blank" 
            rel="nofollow noopener noreferrer">
            &nbsp;Hexo
          </a>
        
        
          <span>&nbsp;|&nbsp;</span>
        
        
          Theme -
          <a 
            href="https://github.com/theme-kaze" 
            class="footer-link" 
            target="_blank"
            rel="nofollow noopener noreferrer">
            &nbsp;Kaze
          </a>
        
      </div>
    
    
    
    
</footer> 
    
  <a 
    role="button" 
    id="scrollbutton" 
    class="basebutton" 
    aria-label="回到顶部">
    <i class="iconfont icon-arrowleft button-icon"></i>
  </a>

<a 
  role="button" 
  id="menubutton" 
  class="basebutton">
  <i class="iconfont icon-menu button-icon"></i>
</a>
<a 
  role="button" 
  id="popbutton" 
  class="basebutton" 
  aria-label="控制中心">
  <i class="iconfont icon-expand button-icon"></i>
</a>
<a 
  role="button" 
  id="darkbutton" 
  class="basebutton darkwidget" 
  aria-label="夜色模式">
  <i class="iconfont icon-weather button-icon"></i>
</a>
<a 
  role="button" 
  id="searchbutton" 
  class="basebutton searchwidget" 
  aria-label="搜索">
  <i class="iconfont icon-search button-icon"></i>
</a> 
     
     
     
      <script>
  var addImgLayout = function () {
    var img = document.querySelectorAll('.post-content img')
    var i
    for (i = 0; i < img.length; i++) {
      var wrapper = document.createElement('a')
      wrapper.setAttribute('href', img[i].getAttribute('data-src'))
      wrapper.setAttribute('aria-label', 'illustration')
      wrapper.style.cssText =
        'width: 100%; display: flex; justify-content: center;'
      if (img[i].alt) wrapper.dataset.caption = img[i].alt
      wrapper.dataset.nolink = true
      img[i].before(wrapper)
      wrapper.append(img[i])
      var divWrap = document.createElement('div')
      divWrap.classList.add('gallery')
      wrapper.before(divWrap)
      divWrap.append(wrapper)
    }
    baguetteBox.run('.gallery')
  }
</script>
<script>
  loadScript(
    "/js/lib/lightbox/baguetteBox.min.js",
    addImgLayout
  )
</script>
 
     
     
    <script src="/js/main.js"></script> 
     
    
      <script>
        var addLazyload = function () {
          var observer = lozad('.lozad', {
            load: function (el) {
              el.srcset = el.getAttribute('data-src')
            },
            loaded: function (el) {
              el.classList.add('loaded')
            },
          })
          observer.observe()
        }
      </script>
      <script>
        loadScript('/js/lib/lozad.min.js', addLazyload)
      </script>
     
    
    
  </body>
</html>
